﻿using System.Windows.Navigation;
using Liphofra.Core.EventAggregation;
using Liphofra.Mvvm.Navigation;
using Microsoft.Phone.Controls;

namespace Liphofra.Mvvm.ViewModels
{
    /// <summary>
    /// An implementation of a view model that is aware of the navigation concepts on Windows Phone.
    /// </summary>
    public abstract class NavigationViewModelBase : ViewModelBase, INavigationViewModel
    {
        /// <summary>
        /// Gets or sets the navigation service that can be used to perform navigation actions from the view model.
        /// </summary>
        public INavigationService NavigationService
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the event aggregator that can be used to take part in loosely coupled event messaging.
        /// </summary>
        public IEventAggregator EventAggregator
        {
            get;
            set;
        }

        #region Internal Mappings

        /// <summary>
        /// Internal helper method that is used to properly invoke the extension points from the view.
        /// </summary>
        internal void InternalOnInitialize()
        {
            OnInitialize();
        }

        /// <summary>
        /// Internal helper method that is used to properly invoke the extension points from the view.
        /// </summary>
        internal void InternalOnRestoreState()
        {
            OnRestoreState();
        }

        /// <summary>
        /// Internal helper method that is used to properly invoke the extension points from the view.
        /// </summary>
        /// <param name="e">The <see cref="NavigationEventArgs"/> instance containing the event data.</param>
        internal void InternalOnNavigatingFrom(NavigatingCancelEventArgs e)
        {
            OnNavigatingFrom(e);
        }

        /// <summary>
        /// Internal helper method that is used to properly invoke the extension points from the view.
        /// </summary>
        /// <param name="e">The <see cref="NavigationEventArgs"/> instance containing the event data.</param>
        internal void InternalOnNavigatingBack(NavigatingCancelEventArgs e)
        {
            OnNavigatingBack(e);
        }

        /// <summary>
        /// Internal helper method that is used to properly invoke the extension points from the view.
        /// </summary>
        /// <param name="e">The <see cref="NavigationEventArgs"/> instance containing the event data.</param>
        internal void InternalOnNavigatingAway(NavigatingCancelEventArgs e)
        {
            OnNavigatingAway(e);
        }

        /// <summary>
        /// Internal helper method that is used to properly invoke the extension points from the view.
        /// </summary>
        /// <param name="e">The <see cref="NavigationEventArgs"/> instance containing the event data.</param>
        internal void InternalOnNavigatedFrom(NavigationEventArgs e)
        {
            OnNavigatedFrom(e);
        }

        /// <summary>
        /// Internal helper method that is used to properly invoke the extension points from the view.
        /// </summary>
        /// <param name="e">The <see cref="NavigationEventArgs"/> instance containing the event data.</param>
        internal void InternalOnNavigatedBack(NavigationEventArgs e)
        {
            OnNavigatedBack(e);
        }

        /// <summary>
        /// Internal helper method that is used to properly invoke the extension points from the view.
        /// </summary>
        /// <param name="e">The <see cref="NavigationEventArgs"/> instance containing the event data.</param>
        internal void InternalOnNavigatedAway(NavigationEventArgs e)
        {
            OnNavigatedAway(e);
        }
        
        /// <summary>
        /// Internal helper method that is used to properly invoke the extension points from the view.
        /// </summary>
        /// <param name="e">The <see cref="NavigationEventArgs"/> instance containing the event data.</param>
        /// <param name="context">The context.</param>
        /// <param name="isNewInstance">if set to <c>true</c> [is new instance].</param>
        internal void InternalOnNavigatedTo(NavigationEventArgs e, NavigationContext context, bool isNewInstance)
        {
            OnNavigatedTo(e, context, isNewInstance);
        }

        #endregion

        #region Protected Extension Points

        /// <summary>
        /// Called when the view model should perform initialization logic.
        /// This typically only is invoked once after the view model is created during a forward navigation.
        /// </summary>
        protected virtual void OnInitialize()
        {
        }

        /// <summary>
        /// Called when the view model should restore its state.
        /// This is typically invoked when the view has been navigated to and a new instance of the 
        /// view model was created as a result of this.
        /// </summary>
        protected virtual void OnRestoreState()
        {
        }

        /// <summary>
        /// Called when the corresponding view is being navigated from.
        /// This is the generic extension point for navigation that happens away from the view model.
        /// The more specific extension points are <see cref="OnNavigatingBack"/> and <see cref="OnNavigatingAway"/>.
        /// </summary>
        /// <param name="e">The <see cref="NavigationEventArgs"/> instance containing the event data.</param>
        protected virtual void OnNavigatingFrom(NavigatingCancelEventArgs e)
        {
        }

        /// <summary>
        /// Called when the corresponding view is being navigated back from.
        /// This typically is the place where a view model should perform validation logic and cancel navigation, if required.
        /// </summary>
        /// <param name="e">The <see cref="NavigatingCancelEventArgs"/> instance containing the event data.</param>
        protected virtual void OnNavigatingBack(NavigatingCancelEventArgs e)
        {
        }

        /// <summary>
        /// Called when the corresponding view is being navigated away from, either to a new page of the same application, or completely away from the application.
        /// </summary>
        /// <param name="e">The <see cref="NavigatingCancelEventArgs"/> instance containing the event data.</param>
        protected virtual void OnNavigatingAway(NavigatingCancelEventArgs e)
        {
        }

        /// <summary>
        /// Called when the corresponding view has been navigated from.
        /// This is the generic extension point navigation that happened away from the view model.
        /// The more specific extension points are <see cref="OnNavigatedBack"/> and <see cref="OnNavigatedAway"/>.
        /// </summary>
        /// <param name="e">The <see cref="NavigationEventArgs"/> instance containing the event data.</param>
        protected virtual void OnNavigatedFrom(NavigationEventArgs e)
        {
        }

        /// <summary>
        /// Called when the corresponding view has been navigated back from.
        /// This typically is the place where a view model should perform data saving, if required.
        /// </summary>
        /// <param name="e">The <see cref="NavigatingCancelEventArgs"/> instance containing the event data.</param>
        protected virtual void OnNavigatedBack(NavigationEventArgs e)
        {
        }

        /// <summary>
        /// Called when the corresponding view is being navigated away from, either to a new page of the same application, or completely away from the application.
        /// This typically is the place where a view model should persist its state, in anticipation of potential tombstoning.
        /// </summary>
        /// <param name="e">The <see cref="NavigatingCancelEventArgs"/> instance containing the event data.</param>
        protected virtual void OnNavigatedAway(NavigationEventArgs e)
        {
        }

        /// <summary>
        /// Called when the corresponding view has been navigated to.
        /// </summary>
        /// <param name="e">The <see cref="NavigationEventArgs"/> instance containing the event data.</param>
        /// <param name="context">The context.</param>
        /// <param name="isNewInstance">if set to <c>true</c> [is new instance].</param>
        protected virtual void OnNavigatedTo(NavigationEventArgs e, NavigationContext context, bool isNewInstance)
        {
        }

        #endregion
    }
}